/*
	The MIT License

	Copyright (c) 2010 IFMO/GameDev Studio

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*/


#include "d3d_local.h"



/*-----------------------------------------------------------------------------
	Texture creators :
-----------------------------------------------------------------------------*/

IPxTexture ED3DTexture::CreateTextureFromFile( ED3DRenderSystem *rs, const char *path )
{
	IPxTexture	tex;
	
	try {
		LOGF("Loading : %s", path);

		//	Virtual texture names :
		if (path[0]=='*') {	
			if (strcmp(path, "*null")  == 0 )	tex = CreateNullTexture(rs);						  else
			if (strcmp(path, "*black") == 0 )	tex = CreateSolidTexture(rs, 0x00, 0x00, 0x00, 0xFF); else
			if (strcmp(path, "*grey")  == 0 )	tex = CreateSolidTexture(rs, 0x80, 0x80, 0x80, 0xFF); else
			if (strcmp(path, "*white") == 0 )	tex = CreateSolidTexture(rs, 0xFF, 0xFF, 0xFF, 0xFF); else
			if (strcmp(path, "*red")   == 0 )	tex = CreateSolidTexture(rs, 0xFF, 0x00, 0x00, 0xFF); else
			if (strcmp(path, "*green") == 0 )	tex = CreateSolidTexture(rs, 0x00, 0xFF, 0x00, 0xFF); else
			if (strcmp(path, "*blue")  == 0 )	tex = CreateSolidTexture(rs, 0x00, 0x00, 0xFF, 0xFF); else
			if (strcmp(path, "*flat")  == 0 )	tex = CreateSolidTexture(rs, 0x80, 0x80, 0xFF, 0x80); else	// flat normal map
			RAISE_EXCEPTION(va("wrong virtual texture name '%s'", path));
		} else {	
			tex	=	LoadTextureFromFile(rs, path);
		}
		
	} catch (exception &e) {	
		LOG_WARNING(e.what());	
		
		tex = CreateNullTexture(rs);
	}
	
	return tex;
}


//
//	ED3DTexture::LoadTextureFromFile
//	- creates texture from file
//
IPxTexture ED3DTexture::LoadTextureFromFile( ED3DRenderSystem *rs, const char *path )
{
	IPxTexture	px_tex	= new ED3DTexture();
	ED3DTexture	*tex	= px_tex.To<ED3DTexture>();

	
	IDirect3DDevice9	*d3ddev = rs->GetDevice();

	//
	//	Read data from disc :
	//	
	IPxFile	file = fs()->FileOpen( path, FS_OPEN_READ );
	
	vector<byte>	buffer;
	buffer.resize(file->Size());
	file->Read(&buffer[0], file->Size());

	uint	file_size	=	file->Size();
	byte	*file_data	=	&buffer[0];

	//	
	//	Retrieve image data :
	//
	D3DXIMAGE_INFO	info;


	if ( FAILED( D3DXGetImageInfoFromFileInMemory(file_data, file_size, &info) ) ) {
		RAISE_EXCEPTION(va("bad texture file '%s'\r\n", path));
	}


	//	TODO : add D3DRTYPE_VOLUMETEXTURE :	
	if (info.ResourceType==D3DRTYPE_TEXTURE) 
	{
		LPDIRECT3DTEXTURE9 d3d_tex;

		if ( FAILED( D3DXCreateTextureFromFileInMemory(d3ddev, file_data, file_size, &d3d_tex) ) ) {
			RAISE_EXCEPTION(va("failed to create 2D texture from '%s'\r\n", path));
		} else {
			tex->d3d_tex	=	d3d_tex;
			tex->width		=	info.Width;
			tex->height		=	info.Height;
			tex->depth		=	info.Depth;
			tex->type		=	RS_TEXTURE_2D;
			tex->format		=	GetRSFormat(info.Format);
		}
	

	} else if (info.ResourceType==D3DRTYPE_CUBETEXTURE) 
	{
		LPDIRECT3DCUBETEXTURE9 d3d_tex;
		
		if ( FAILED( D3DXCreateCubeTextureFromFileInMemory(d3ddev, file_data, file_size, &d3d_tex) ) ) {
			RAISE_EXCEPTION(va("failed to create CUBE texture from '%s'\r\n", path));
		} else {
			tex->d3d_tex	=	d3d_tex;
			tex->width		=	info.Width;
			tex->height		=	info.Height;
			tex->depth		=	info.Depth;
			tex->type		=	RS_TEXTURE_CUBE;
			tex->format		=	GetRSFormat(info.Format);
		}
	

	} else 
	{
		RAISE_EXCEPTION("Unsupported resource type");
	}
	
	return px_tex;
}


//
//	ED3DTexture::CreateTexture2D
//	- creates simple 2D texture filled with black.
//
IPxTexture ED3DTexture::CreateTexture2D( ED3DRenderSystem *rs, uint w, uint h, ERSFormat_t frmt )
{
	IPxTexture	px_tex	= new ED3DTexture();
	ED3DTexture	*tex	= px_tex.To<ED3DTexture>();
	
	return px_tex;
}


//
//	ED3DTexture::CreateNullTexture
//	- creates texture, that can be accepted by D3D device,
//	  but does not contain any data.
//
IPxTexture ED3DTexture::CreateNullTexture( ED3DRenderSystem *rs )
{
	IPxTexture	px_tex	= new ED3DTexture();
	ED3DTexture	*tex	= px_tex.To<ED3DTexture>();

	LPDIRECT3DTEXTURE9 d3d_tex;
	HRCALL( rs->GetDevice()->CreateTexture(16,16, 0, D3DUSAGE_AUTOGENMIPMAP, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &d3d_tex, NULL) );
	
	tex->width	= 16;
	tex->height	= 16;
	tex->format	= RS_FORMAT_ARGB_U8;
	tex->type	= RS_TEXTURE_2D;

	D3DLOCKED_RECT rect;	
	HRCALL( d3d_tex->LockRect(0, &rect, NULL, 0) );

		byte *ptr = (byte*)rect.pBits;	
		for (uint x=0; x<16; x++) {
			for (uint y=0; y<16; y++) {
				
				byte clr[4];
				
				// All surface should be BLACK :
				clr[0] = clr[1] = clr[2] = 0x00;
				clr[3] = 0xFF;
				
				if ((x^y)&1) {				// PINK squares, it is so emotinaly
					clr[0] = clr[2] = 0xFF;	
				}
				
				if (x==15 || y==15) {		// YELLOW edge to view mapping.
					clr[0] = clr[1] = 0xFF;
					clr[2] = 0x00;
				}
				
				ptr[ y*rect.Pitch + x*4 + 0 ] = clr[2];
				ptr[ y*rect.Pitch + x*4 + 1 ] = clr[1];
				ptr[ y*rect.Pitch + x*4 + 2 ] = clr[0];
				ptr[ y*rect.Pitch + x*4 + 3 ] = clr[3];
			}
		}
	
	HRCALL( d3d_tex->UnlockRect(0) );
	
	tex->d3d_tex	=	d3d_tex;
	
	return px_tex;
}


//
//	ED3DTexture::CreateSolidTexture
//
IPxTexture ED3DTexture::CreateSolidTexture( ED3DRenderSystem *rs, uchar r, uchar g, uchar b, uchar a )
{
	IPxTexture	px_tex	= new ED3DTexture();
	ED3DTexture	*tex	= px_tex.To<ED3DTexture>();

	LPDIRECT3DTEXTURE9 d3d_tex;
	HRCALL( rs->GetDevice()->CreateTexture(16,16, 0, D3DUSAGE_AUTOGENMIPMAP, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &d3d_tex, NULL) );
	
	tex->width	= 16;
	tex->height	= 16;
	tex->format	= RS_FORMAT_ARGB_U8;
	tex->type	= RS_TEXTURE_2D;

	D3DLOCKED_RECT rect;	
	HRCALL( d3d_tex->LockRect(0, &rect, NULL, 0) );

		byte *ptr = (byte*)rect.pBits;	
		for (uint x=0; x<16; x++) {
			for (uint y=0; y<16; y++) {
				byte clr[4] = {r,g,b,a};
				
				ptr[ y*rect.Pitch + x*4 + 0 ] = clr[2];
				ptr[ y*rect.Pitch + x*4 + 1 ] = clr[1];
				ptr[ y*rect.Pitch + x*4 + 2 ] = clr[0];
				ptr[ y*rect.Pitch + x*4 + 3 ] = clr[3];
			}
		}
	
	HRCALL( d3d_tex->UnlockRect(0) );
	
	d3d_tex	=	d3d_tex;

	tex->d3d_tex	=	d3d_tex;
	return px_tex;
}

/*-----------------------------------------------------------------------------
	Texture :
-----------------------------------------------------------------------------*/

//
//	ED3DTexture::ED3DTexture
//
ED3DTexture::ED3DTexture(void )
{
	width	=	0;
	height	=	0;
	depth	=	0;
	format	=	RS_FORMAT_UNKNOWN;
	type	=	RS_TEXTURE_UNKNOWN;
	
	d3d_tex	=	NULL;
}


//
//	ED3DTexture::~ED3DTexture
//
ED3DTexture::~ED3DTexture( void )
{
	SAFE_RELEASE( d3d_tex );
}


//
//	ED3DTexture::WriteData2D
//	TODO : implement WriteData2D
//
void ED3DTexture::WriteData2D( const void *data, uint w, uint h, uint pitch )
{
	
}

